package com.quad.innovators.salesease.service.impl;

import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.quad.innovators.salesease.cache.CaptchaCache;
import com.quad.innovators.salesease.cache.UserTokenCache;
import com.quad.innovators.salesease.common.utils.DateUtils;
import com.quad.innovators.salesease.common.utils.SmUtils;
import com.quad.innovators.salesease.config.property.CaptchaProperties;
import com.quad.innovators.salesease.config.property.LoginInfoConfig;
import com.quad.innovators.salesease.constants.SecurityConstants;
import com.quad.innovators.salesease.enums.CaptchaTypeEnum;
import com.quad.innovators.salesease.enums.ResultCode;
import com.quad.innovators.salesease.exception.BusinessException;
import com.quad.innovators.salesease.model.dto.CaptchaResult;
import com.quad.innovators.salesease.model.dto.LoginResult;
import com.quad.innovators.salesease.model.dto.SysUserAuthInfo;
import com.quad.innovators.salesease.model.query.LoginQuery;
import com.quad.innovators.salesease.service.AuthService;
import com.quad.innovators.salesease.service.SysUserService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.awt.*;
import java.util.Date;
import java.util.Objects;


@Service
@RequiredArgsConstructor
@Slf4j
public class AuthServiceImpl implements AuthService {

    private final SysUserService sysUserService;
    private final CodeGenerator codeGenerator;
    private final Font captchaFont;
    private final CaptchaProperties captchaProperties;
    private final UserTokenCache userTokenCache;
    private final LoginInfoConfig loginInfoConfig;
    private final CaptchaCache captchaCache;

    @Override
    public LoginResult login(LoginQuery loginQuery) {
        // 判断验证码是否为空，不为空校验验证码
        String captchaKey = loginQuery.getCaptchaKey();
        String captchaResult = loginQuery.getCaptchaResult();
        if(StrUtil.isNotBlank(captchaKey)) {
            String captcha = captchaCache.get(captchaKey);
            if(StrUtil.isBlank(captcha) || StrUtil.equals(captcha, captchaResult)) {
                throw new BusinessException(ResultCode.LOGIN_CAPTCHA_ERROR.getCode(),ResultCode.LOGIN_CAPTCHA_ERROR.getMsg());
            }
        }
        // 查询用户是否存在
        SysUserAuthInfo userAuthInfo = sysUserService.getUserAuthInfo(loginQuery.getTelephone());
        if(userAuthInfo == null) {
            throw new BusinessException(ResultCode.USERNAME_OR_PASSWORD_ERROR.getCode(),ResultCode.USERNAME_OR_PASSWORD_ERROR.getMsg());
        }
        // 比较密码是否一致
        String rightPassword = userAuthInfo.getPassword();
        String currentPassword = SmUtils.sm4Encrypt(loginQuery.getPassword());

        if(!StrUtil.equals(currentPassword, rightPassword)) {
            throw new BusinessException(ResultCode.USERNAME_OR_PASSWORD_ERROR.getCode(),ResultCode.USERNAME_OR_PASSWORD_ERROR.getMsg());
        }
        // 创建缓存对象，生成token
        String token = createToken(userAuthInfo);
        // 缓存对象
        userTokenCache.set(token, userAuthInfo, loginInfoConfig.getCookieTimeout());
        // 返回包含JWT令牌的登录结果
        return LoginResult.builder()
                .tokenType("Bearer")
                .accessToken(token)
                .expires(loginInfoConfig.getCookieTimeout())
                .build();
    }

    /**
     * 注销
     */
    @Override
    public void logout() {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (StrUtil.isNotBlank(token) && token.startsWith(SecurityConstants.TOKEN_PREFIX)) {
            token = token.substring(SecurityConstants.TOKEN_PREFIX.length());
            // 删除用户信息
            userTokenCache.remove(token);
        }
    }


    @Override
    public CaptchaResult getCaptcha() {

        String captchaType = captchaProperties.getType();
        int width = captchaProperties.getWidth();
        int height = captchaProperties.getHeight();
        int interfereCount = captchaProperties.getInterfereCount();
        int codeLength = captchaProperties.getCode().getLength();

        AbstractCaptcha captcha;
        if (CaptchaTypeEnum.CIRCLE.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createCircleCaptcha(width, height, codeLength, interfereCount);
        } else if (CaptchaTypeEnum.GIF.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createGifCaptcha(width, height, codeLength);
        } else if (CaptchaTypeEnum.LINE.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createLineCaptcha(width, height, codeLength, interfereCount);
        } else if (CaptchaTypeEnum.SHEAR.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createShearCaptcha(width, height, codeLength, interfereCount);
        } else {
            throw new IllegalArgumentException("Invalid captcha type: " + captchaType);
        }
        captcha.setGenerator(codeGenerator);
        captcha.setTextAlpha(captchaProperties.getTextAlpha());
        captcha.setFont(captchaFont);

        String captchaCode = captcha.getCode();
        String imageBase64Data = captcha.getImageBase64Data();

        // 验证码文本缓存至Redis，用于登录校验
        String captchaKey = IdUtil.fastSimpleUUID();
        captchaCache.set(SecurityConstants.CAPTCHA_CODE_PREFIX + captchaKey, captchaCode);
        return CaptchaResult.builder()
                .captchaKey(captchaKey)
                .captchaBase64(imageBase64Data)
                .build();
    }


    /**
     * 生成用户登陆的token
     * @param userAuthInfo 用户信息
     * @return token
     */
    private String createToken(SysUserAuthInfo userAuthInfo){
        // token组成： token 5位 + 随机字母2位 +时间戳 14位+ 用户code + 随机数 8位 + 校验位6位
        String random = IdUtil.nanoId(2);
        String timestamp = DateUtils.dateFormat(new Date(), DateUtils.DATE_TO_SECOND_STRING);
        String userCode = userAuthInfo.getUserCode();
        String random2 = IdUtil.nanoId(8);
        String token = String.format("%s%s%s%s%s", "token", random, timestamp,userCode,random2);
        String check = SmUtils.sm3Encrypt(token).substring(Math.max(0, token.length() -6), token.length());
        return String.format("%s%s", token, check);
    }
}
